// 语音识别和语音合成服务

import { SpeechResult } from '../types';

// 声明全局类型
declare global {
  interface Window {
    webkitSpeechRecognition: any;
    SpeechRecognition: any;
  }
}

class SpeechService {
  private recognition: any = null;
  private synthesis: SpeechSynthesis;
  private isListening: boolean = false;
  
  constructor() {
    this.synthesis = window.speechSynthesis;
    this.initSpeechRecognition();
  }

  // 初始化语音识别
  private initSpeechRecognition(): void {
    if ('webkitSpeechRecognition' in window) {
      this.recognition = new (window as any).webkitSpeechRecognition();
    } else if ('SpeechRecognition' in window) {
      this.recognition = new (window as any).SpeechRecognition();
    }

    if (this.recognition) {
      this.recognition.continuous = false;
      this.recognition.interimResults = false;
      this.recognition.lang = 'en-US';
      this.recognition.maxAlternatives = 1;
    }
  }

  // 检查语音功能支持
  isSupported(): boolean {
    return !!(this.recognition && this.synthesis);
  }

  // 开始语音识别
  async startListening(): Promise<SpeechResult> {
    return new Promise((resolve, reject) => {
      if (!this.recognition) {
        reject(new Error('语音识别不支持'));
        return;
      }

      // 如果正在监听，先停止
      if (this.isListening) {
        this.stopListening();
        // 等待短暂时间让语音识别完全停止
        setTimeout(() => this.startListeningInternal(resolve, reject), 100);
        return;
      }

      this.startListeningInternal(resolve, reject);
    });
  }

  // 内部语音识别启动方法
  private startListeningInternal(resolve: (value: SpeechResult) => void, reject: (reason?: any) => void): void {
    // 确保重置状态
    this.isListening = false;
    
    // 重新初始化语音识别以确保干净状态
    this.initSpeechRecognition();
    
    if (!this.recognition) {
      reject(new Error('语音识别初始化失败'));
      return;
    }

    this.isListening = true;

    // 设置事件监听器
    this.recognition.onresult = (event) => {
      console.log('🎤 语音识别结果:', event.results);
      const result = event.results[0];
      const transcript = result[0].transcript;
      const confidence = result[0].confidence;
      
      this.isListening = false;
      resolve({
        transcript: transcript.trim(),
        confidence: confidence,
        accuracy: this.calculateAccuracy(transcript, confidence)
      });
    };

    this.recognition.onerror = (event) => {
      console.error('🚨 语音识别错误:', event.error);
      this.isListening = false;
      reject(new Error(`语音识别错误: ${event.error}`));
    };

    this.recognition.onend = () => {
      console.log('🔚 语音识别结束');
      if (this.isListening) {
        // 如果仍标记为正在监听，说明可能是异常结束
        this.isListening = false;
        reject(new Error('语音识别意外结束'));
      }
    };

    this.recognition.onstart = () => {
      console.log('🎤 语音识别开始');
    };

    try {
      console.log('🚀 启动语音识别...');
      this.recognition.start();
    } catch (error) {
      console.error('❌ 启动语音识别失败:', error);
      this.isListening = false;
      reject(error);
    }
  }

  // 停止语音识别
  stopListening(): void {
    console.log('🛑 停止语音识别');
    if (this.recognition) {
      try {
        this.recognition.stop();
      } catch (error) {
        console.warn('停止语音识别时出错:', error);
      }
    }
    this.isListening = false;
  }

  // 语音合成（朗读单词）
  async speak(text: string, options: { rate?: number, pitch?: number, volume?: number } = {}): Promise<void> {
    return new Promise((resolve, reject) => {
      if (!this.synthesis) {
        reject(new Error('语音合成不支持'));
        return;
      }

      // 停止当前播放
      this.synthesis.cancel();

      const utterance = new SpeechSynthesisUtterance(text);
      utterance.lang = 'en-US';
      utterance.rate = options.rate || 0.8;
      utterance.pitch = options.pitch || 1;
      utterance.volume = options.volume || 1;

      utterance.onend = () => resolve();
      utterance.onerror = (event) => reject(new Error(`语音合成错误: ${event.error}`));

      this.synthesis.speak(utterance);
    });
  }

  // 停止语音合成
  stopSpeaking(): void {
    if (this.synthesis) {
      this.synthesis.cancel();
    }
  }

  // 计算发音准确度
  calculatePronunciationAccuracy(target: string, spoken: string): number {
    const targetWords = target.toLowerCase().split(' ');
    const spokenWords = spoken.toLowerCase().split(' ');
    
    if (targetWords.length === 0) return 0;
    
    let matches = 0;
    for (const targetWord of targetWords) {
      if (spokenWords.some(spokenWord => 
        this.calculateWordSimilarity(targetWord, spokenWord) > 0.7
      )) {
        matches++;
      }
    }
    
    return (matches / targetWords.length) * 100;
  }

  // 计算单词相似度
  private calculateWordSimilarity(word1: string, word2: string): number {
    const maxLength = Math.max(word1.length, word2.length);
    if (maxLength === 0) return 1;
    
    const distance = this.levenshteinDistance(word1, word2);
    return (maxLength - distance) / maxLength;
  }

  // 计算编辑距离
  private levenshteinDistance(str1: string, str2: string): number {
    const matrix = [];
    
    for (let i = 0; i <= str2.length; i++) {
      matrix[i] = [i];
    }
    
    for (let j = 0; j <= str1.length; j++) {
      matrix[0][j] = j;
    }
    
    for (let i = 1; i <= str2.length; i++) {
      for (let j = 1; j <= str1.length; j++) {
        if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
          matrix[i][j] = matrix[i - 1][j - 1];
        } else {
          matrix[i][j] = Math.min(
            matrix[i - 1][j - 1] + 1,
            matrix[i][j - 1] + 1,
            matrix[i - 1][j] + 1
          );
        }
      }
    }
    
    return matrix[str2.length][str1.length];
  }

  // 计算准确度（综合置信度和其他因素）
  private calculateAccuracy(transcript: string, confidence: number): number {
    // 基于置信度和文本质量计算准确度
    let accuracy = confidence * 100;
    
    // 根据文本长度调整
    if (transcript.length < 3) {
      accuracy *= 0.8;
    }
    
    // 根据单词数量调整
    const wordCount = transcript.split(' ').length;
    if (wordCount > 1) {
      accuracy *= 0.9;
    }
    
    return Math.min(100, Math.max(0, accuracy));
  }

  // 获取当前状态
  getStatus(): { isListening: boolean, isSupported: boolean } {
    return {
      isListening: this.isListening,
      isSupported: this.isSupported()
    };
  }
}

export const speechService = new SpeechService();